﻿using System;
using System.Collections.Generic;
using System.Linq;
using Loki.Engine;
using Luna.Data.Accounting;
using Luna.Model.Accounting;
using NUnit.Framework;

namespace Luna.Data.Tests
{
    public class OtherOperationTest : AssertionHelper
    {
        public IOtherOperationData Operation1 { get; set; }
        public IOtherOperationData Operation2 { get; set; }
        public IOtherOperationData Operation3 { get; set; }

        public IAccountData MainAccount { get; set; }
        public INamedEntityData MainCategory { get; set; }

        private bool AreSame(IOtherOperationData P_Op1, IOtherOperationData P_Op2)
        {
            bool b = true;
            b &= P_Op1.PK == P_Op2.PK;
            b &= P_Op1.AccountID == P_Op2.AccountID;
            b &= P_Op1.Amount == P_Op2.Amount;
            b &= P_Op1.CategoryID == P_Op2.CategoryID;
            b &= P_Op1.Description == P_Op2.Description;
            b &= P_Op1.ExecutionDate == P_Op2.ExecutionDate;
            b &= P_Op1.OperationType == P_Op2.OperationType;
            b &= P_Op1.ValueDate == P_Op2.ValueDate;
            return b;
        }

        public IAccountingDataProvider Data { get; set; }

        private IAccountData CreateAccount(string P_Name)
        {
            IAccountData L_Return = Data.Create<IAccountData>();
            L_Return.PK = Guid.NewGuid();
            L_Return.Number = P_Name + "Number";
            L_Return.Name = P_Name + "Name";
            L_Return.Bank = P_Name + "Bank";
            L_Return.InitialAmount = P_Name.Length;
            L_Return.StartDate = DateTime.Today.AddDays(P_Name.Length);
            return L_Return;
        }

        private INamedEntityData CreateCategory(string P_Name)
        {
            INamedEntityData L_Return = Data.Create<INamedEntityData>();
            L_Return.PK = Guid.NewGuid();
            L_Return.Name = P_Name + "_Name";
            L_Return.Description = P_Name + "_Description";
            return L_Return;
        }

        private IOtherOperationData Create(string P_Name, Guid P_AccountID, Guid P_CategoryID)
        {
            IOtherOperationData L_Return = Data.Create<IOtherOperationData>();
            L_Return.PK = Guid.NewGuid();
            L_Return.AccountID = P_AccountID;
            L_Return.CategoryID = P_CategoryID;
            L_Return.Amount = 1000.25m;
            L_Return.ExecutionDate = DateTime.Today;
            L_Return.OperationType = AccountOperationType.Others;
            L_Return.ValueDate = new DateTime(1980, 01, 14);
            L_Return.Description = P_Name + "_Description";
            return L_Return;
        }

        [SetUp]
        public void SetUp()
        {
            Data = ContextHelper.GetDataModel<LunaDataModel>().Accounting;

            MainAccount = CreateAccount("Account");
            MainCategory = CreateCategory("Category");

            Operation1 = Create("Operation1", MainAccount.PK, MainCategory.PK);
            Operation2 = Create("Operation2", MainAccount.PK, MainCategory.PK);
            Operation3 = Create("Operation3", MainAccount.PK, MainCategory.PK);

            CleanTable();
        }

        [TearDown]
        public void CleanTable()
        {
            IEnumerable<IOtherOperationData> L_Operations = Data.GetAllOtherOperations().Where(x => x.ValueDate == new DateTime(1980, 01, 14));
            foreach (var L_Op in L_Operations)
            {
                Data.DeleteOtherOperation(L_Op.PK);
            }

            foreach (var L_Op in L_Operations)
            {
                Data.DeleteAccount(L_Op.AccountID);
            }

            foreach (var L_Op in L_Operations)
            {
                Data.DeleteCategory(L_Op.CategoryID);
            }
        }

        [Test]
        public void TestGetAllByAccount()
        {
            Data.SaveAccount(MainAccount);
            Data.SaveCategory(MainCategory);

            Data.SaveOtherOperation(Operation1);

            IEnumerable<IOtherOperationData> L_Operations = Data.GetAllOtherOperationsByAccount(MainAccount.PK);
            Expect(L_Operations.Count(), EqualTo(1));
        }

        [Test]
        public void TestInsertAndGet()
        {
            Data.SaveAccount(MainAccount);
            Data.SaveCategory(MainCategory);

            Data.SaveOtherOperation(Operation1);
            IOtherOperationData L_Operation = Data.GetOtherOperation(Operation1.PK);
            Expect(AreSame(Operation1, L_Operation), Is.True);
        }

        [Test]
        public void TestUpdateAndGet()
        {
            Data.SaveAccount(MainAccount);
            Data.SaveCategory(MainCategory);

            Data.SaveOtherOperation(Operation1);
            Operation1.Description = "Operation1_Name_Modified";
            Data.SaveOtherOperation(Operation1);

            IOtherOperationData L_Operation = Data.GetOtherOperation(Operation1.PK);
            Expect(AreSame(Operation1, L_Operation), Is.True);

            Expect(L_Operation.Description, Is.EqualTo("Operation1_Name_Modified"));
        }

        [Test]
        public void TestInsertAndGetAll()
        {
            Data.SaveAccount(MainAccount);
            Data.SaveCategory(MainCategory);

            Data.SaveOtherOperation(Operation1);
            Data.SaveOtherOperation(Operation2);
            Data.SaveOtherOperation(Operation3);

            int L_Count = Data.GetAllOtherOperations().Count();
            Expect(L_Count, Is.EqualTo(3));
        }

        [Test]
        public void TestInsertAndDelete()
        {
            Data.SaveAccount(MainAccount);
            Data.SaveCategory(MainCategory);

            Data.SaveOtherOperation(Operation1);
            Data.SaveOtherOperation(Operation2);
            Data.DeleteOtherOperation(Operation1.PK);

            int L_Count = Data.GetAllOtherOperations().Count();
            Expect(L_Count, Is.EqualTo(1));
            IOtherOperationData L_Account = Data.GetOtherOperation(Operation1.PK);
            Expect(L_Account, Is.Null);
        }

        [Test]
        public void TestNoAccount()
        {
            Data.SaveCategory(MainCategory);
            Expect(() => Data.SaveOtherOperation(Operation1), Throws.Exception);
        }

        [Test]
        public void TestNoCategory()
        {
            Data.SaveAccount(MainAccount);
            Expect(() => Data.SaveOtherOperation(Operation1), Throws.Exception);
        }
    }
}
